<template>
  <view class="arco-slider">
    <view ref="trackRef" :class="trackCls">
      <view class="arco-slider-bar" :style="style"> </view>
      <sliderTicks
        v-if="showTicks"
        :value="computedValue"
        :step="step"
        :min="min"
        :max="max"
        :direction="direction"
      ></sliderTicks>
      <sliderMarks
        v-if="marks"
        :direction="direction"
        :data="markList"
        :min="min"
        :max="max"
      >
      </sliderMarks>
      <sliderDots
        v-if="marks"
        :direction="direction"
        :data="markList"
        :min="min"
        :max="max"
      >
      </sliderDots>
      <sildeButton
        :style="getBtnStyle(computedValue[1])"
        :disabled="mergedDisabled"
        :min="min"
        :direction="direction"
        :max="max"
        @moving="handleStartMoving"
        @moveend="handleMoveEnd"
        @movestart="handleMoveStart"
      ></sildeButton>
    </view>
  </view>
</template>

<script lang="ts">
import { useFormItem } from "@/ArcoUni/hook/use-form-item";
import {
  computed,
  defineComponent,
  getCurrentInstance,
  ref,
  toRefs,
} from "vue";
import { isArray, isUndefined } from "@/utils/is";
import sildeButton from "./slider-button.vue";
import sliderTicks from "./slider-ticks.vue";
import sliderMarks from "./slider-marks.vue";
import sliderDots from "./slider-dots.vue";
const Slider = defineComponent({
  name: "Slider",
  options: {
    // 虚拟化节点
    virtualHost: true,
  },
  components: {
    sildeButton,
    sliderTicks,
    sliderMarks,
    sliderDots,
  },
  props: {
    modelValue: {
      type: [Number, Array],
      default: void 0,
    },
    defaultValue: {
      type: [Number, Array],
      default: 0,
    },
    step: {
      type: Number,
      default: 1,
    },
    min: {
      type: Number,
      default: 0,
    },
    marks: {
      type: Object,
    },
    max: {
      type: Number,
      default: 100,
    },
    direction: {
      type: String,
      default: "horizontal",
    },
    disabled: {
      type: Boolean,
      default: false,
    },
    showTicks: {
      type: Boolean,
      default: false,
    },
    showInput: {
      type: Boolean,
      default: false,
    },
    range: {
      type: Boolean,
      default: false,
    },
    formatTooltip: {
      type: Function,
    },
    showTooltip: {
      type: Boolean,
      default: true,
    },
  },
  emits: ["update:modelValue", "change"],
  setup(props, { emit }) {
    const { disabled, modelValue } = toRefs(props);
    const prefixCls = "arco-slider";
    const trackRef = ref();

    const { proxy } = getCurrentInstance() as any;

    // eventHandlers
    const { mergedDisabled } = useFormItem({
      disabled,
    });

    const defaultValue = modelValue.value
      ? modelValue.value
      : props.defaultValue;

    const startValue = ref(isArray(defaultValue) ? defaultValue[0] : 0);
    const endValue = ref(
      isArray(defaultValue) ? defaultValue[1] : defaultValue,
    );

    const computedValue = computed(() => {
      var _a, _b, _c;
      if (props.range) {
        if (isArray(props.modelValue)) {
          return props.modelValue;
        }
        return [
          startValue.value,
          (_a = props.modelValue) != null ? _a : endValue.value,
        ];
      }
      if (isUndefined(props.modelValue)) {
        return [startValue.value, endValue.value];
      }
      if (isArray(props.modelValue)) {
        return [(_b = props.min) != null ? _b : 0, props.modelValue[1]];
      }
      return [(_c = props.min) != null ? _c : 0, props.modelValue];
    });

    const markList = computed(() =>
      Object.keys(props.marks || {}).map((index) => {
        var _a;
        const key = Number(index);
        return {
          key,
          content: (_a = props.marks) == null ? void 0 : _a[key],
          isActive:
            key >= computedValue.value[0] && key <= computedValue.value[1],
        };
      }),
    );

    function getBarStyle([start, end]) {
      if (start > end) {
        [start, end] = [end, start];
      }
      return props.direction === "vertical"
        ? {
            bottom: getOffsetPercent(start, [props.min, props.max]),
            top: getOffsetPercent(props.max + props.min - end, [
              props.min,
              props.max,
            ]),
          }
        : {
            left: getOffsetPercent(start, [props.min, props.max]),
            right: getOffsetPercent(props.max + props.min - end, [
              props.min,
              props.max,
            ]),
          };
    }

    const getBtnStyle = (value) =>
      getPositionStyle(
        getOffsetPercent(value, [props.min, props.max]),
        props.direction,
      );

    let nodeRef = null;

    function getValueByCoords(x, y) {
      if (!nodeRef) {
        return 0;
      }
      const { left, top, width, height } = nodeRef;
      const trackLength = props.direction === "horizontal" ? width : height;
      const stepLength = (trackLength * props.step) / (props.max - props.min);
      let diff = props.direction === "horizontal" ? x - left : top + height - y;
      if (diff < 0) diff = 0;
      if (diff > trackLength) diff = trackLength;
      const steps = Math.round(diff / stepLength);
      // return NP__default["default"].plus(
      //   props.min,
      //   NP__default["default"].times(steps, props.step),
      // );
      const result = calculateValue(props.min, steps, props.step);
      return result;
    }

    const handleMoveStart = () => {
      // isDragging.value = true;
      // if (trackRef.value) {
      //   trackRect.value = trackRef.value.getBoundingClientRect();
      // }
      const query = uni.createSelectorQuery().in(proxy);
      query
        .select(".arco-slider-track")
        .boundingClientRect((data) => {
          nodeRef = data;
        })
        .exec();
    };

    const handleStartMoving = (x, y) => {
      endValue.value = getValueByCoords(x, y);
      handleChange();
    };

    const handleMoveEnd = () => {
      // isDragging.value = false;
    };

    const classNames = computed(() => {
      return [
        prefixCls,
        {
          [`${prefixCls}-disabled`]: mergedDisabled.value,
        },
      ];
    });

    const trackCls = computed(() => [
      `${prefixCls}-track`,
      {
        [`${prefixCls}-track-disabled`]: mergedDisabled.value,
        [`${prefixCls}-track-vertical`]: props.direction === "vertical",
      },
    ]);

    const handleChange = () => {
      // var _a, _b;
      if (props.range) {
        emit("update:modelValue", [startValue.value, endValue.value]);
        emit("change", [startValue.value, endValue.value]);
      } else {
        emit("update:modelValue", endValue.value);
        emit("change", endValue.value);
      }
      // (_b = (_a = eventHandlers.value) == null ? void 0 : _a.onChange) == null
      //   ? void 0
      //   : _b.call(_a);
    };

    const getOffsetPercent = (value, [min, max]) => {
      const percent = Math.max((value - min) / (max - min), 0);
      return `${Math.round(percent * 10000) / 100}%`;
    };

    const getPositionStyle = (offset, direction) => {
      return direction === "vertical" ? { bottom: offset } : { left: offset };
    };

    function calculateValue(min, steps, step) {
      const product = steps * step;
      const result = min + product;
      return result;
    }

    const style = computed(() => {
      return getBarStyle(computedValue.value as any);
    });

    return {
      prefixCls,
      trackCls,
      classNames,
      markList,
      trackRef,
      getBtnStyle,
      computedValue,
      mergedDisabled,
      style,
      handleMoveStart,
      handleStartMoving,
      handleMoveEnd,
    };
  },
});
export default Slider;
</script>
